﻿using System;
using System.Data;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using PoSHEditor;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
using System.Collections.ObjectModel;

namespace UnitTests.ScriptEngineTests
{
    [TestFixture]
    public class TestScriptEngine
    {
        [Test]
        public void RunspaceLoads()
        {
            Runspace rs = Singletons.TheScriptEngine.TheRunspace;
            Assert.IsNotNull(rs);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void TheScriptEngineLoads()
        {
            ScriptEngine target = Singletons.TheScriptEngine;
            Assert.IsNotNull(target);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void InvokeScriptResultsNotNull()
        {
            Collection<PSObject> result = Singletons.TheScriptEngine.InvokeScript("");

            Assert.IsNotNull(result);
            Assert.IsAssignableFrom(typeof(Collection<PSObject>), result);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void InvokeScriptResultsIsCollectionOfPSObjects()
        {
            Collection<PSObject> result = Singletons.TheScriptEngine.InvokeScript("");
            Assert.IsAssignableFrom(typeof(Collection<PSObject>), result);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void SetAndRetrieveFunction()
        {
            Singletons.TheScriptEngine.InvokeScript("function test {'hello'}");
            Collection<PSObject> results = Singletons.TheScriptEngine.InvokeScript("gc function:test");

            Assert.IsNotNull(results);
            Assert.AreEqual("'hello'", results[0].BaseObject.ToString());

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        [ExpectedException(typeof(System.Management.Automation.CommandNotFoundException))]
        public void InvalidCommand()
        {
            Singletons.TheScriptEngine.InvokeScript("abc");

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void InvokeScriptResults()
        {
            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults("get-date");

            Assert.IsNotNull(results);
            Assert.AreEqual(1, results.PSObjects.Count);
            Assert.IsInstanceOfType(typeof(DateTime), results.PSObjects[0].BaseObject);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void InvokeScriptResultsInvalidCommand()
        {
            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults("abc");

            Assert.IsNotNull(results);
            Assert.IsNull(results.PSObjects);
            Assert.IsNotNull(results.Exception);
            Assert.IsInstanceOfType(typeof(System.Management.Automation.CommandNotFoundException), results.Exception);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void InvokeScriptResultsDifferentTypes()
        {
            List<object> tests = new List<object>();
            InvokeScriptResults results = null;

            //tests.Add("'hello'");
            //tests.Add("1.0");
            //tests.Add("1");
            //tests.Add("get-date");
            //tests.Add("(get-date).Month");
            //tests.Add("dir | select fullname");
            //tests.Add("$x='world';$x*3");
            //tests.Add("$x=1;$x*3");

            DataSet ds = new DataSet();
            ds.Tables.Add("TestTable");
            ds.Tables[0].Columns.Add("Name");
            ds.Tables[0].Columns.Add("Age");


            for (int i = 0; i < 10; i++)
                ds.Tables[0].Rows.Add(new object[] { "test " + i, i });

            Singletons.TheScriptEngine.SetVariable("ds", ds);
            tests.Add("$ds.Tables | Select-Object -Expand Rows");
            Singletons.TheScriptEngine.AddCommand("Out-String");

            foreach (string item in tests)
            {
                results = Singletons.TheScriptEngine.InvokeScriptWithResults(item.ToString());

                if (results.Exception == null)
                {
                    foreach (PSObject x in results.PSObjects)                    
                        System.Diagnostics.Debug.WriteLine(x.ToString());
                }
                else
                    System.Diagnostics.Debug.WriteLine(results.Exception.Message);
            }

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void SetVariableSimple()
        {
            Singletons.TheScriptEngine.SetVariable("test", 1);

            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults("$test");

            Assert.IsNotNull(results);
            Assert.IsNotNull(results.PSObjects);
            Assert.IsNull(results.Exception);
            int expected = 1;
            Assert.IsNotNull(results.PSObjects[0]);

            Assert.AreEqual(expected, results.PSObjects[0].BaseObject);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void SetVariableDataSet()
        {
            Singletons.TheScriptEngine.SetVariable("ds", new DataSet());

            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults("$ds");

            Assert.IsNotNull(results);
            Assert.IsNotNull(results.PSObjects);
            Assert.IsNull(results.Exception);
            Assert.IsNotNull(results.PSObjects[0]);

            Assert.IsInstanceOfType(typeof(DataSet), results.PSObjects[0].BaseObject);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void AddCommand()
        {
            Singletons.TheScriptEngine.AddCommand("Out-String");
            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults(@"get-date");

            System.Diagnostics.Debug.WriteLine(results.PSObjects[0].BaseObject);

            Singletons.ReleaseScriptEngine();
        }

        [Test]
        public void AddOutString()
        {
            Singletons.TheScriptEngine.AddOutString(true);
            InvokeScriptResults results = Singletons.TheScriptEngine.InvokeScriptWithResults(@"ps");

            System.Diagnostics.Debug.WriteLine(results.PSObjects[0].BaseObject);

            Singletons.ReleaseScriptEngine();
        }
    }
}